import type { App, ObjectDirective, DirectiveBinding } from 'vue';

/**
 * 鼠标进入图片放大效果
 * */

// 指令配置类型
interface ImgZoomOptions {
  scale?: number; // 放大倍数（默认1.1）
  duration?: number; // 动画时长（秒，默认0.3）
  origin?: string; // 缩放原点（默认"center center"）
}

// 默认配置
const DEFAULT_OPTIONS: ImgZoomOptions = {
  scale: 1.1,
  duration: 0.3,
  origin: 'center center',
};

// 注入全局过渡样式
const injectGlobalStyles = () => {
  if (document.getElementById('v-img-zoom-styles')) return;

  const style = document.createElement('style');
  style.id = 'v-img-zoom-styles';
  style.textContent = `
    .v-img-zoom {
      transition: transform 0.3s ease !important;
      transform-origin: center center;
    }
    /* 容器需要隐藏溢出，避免放大时超出边界 */
    .v-img-zoom-container {
      overflow: hidden;
      display: inline-block;
    }
  `;
  document.head.appendChild(style);
};

// 指令逻辑
const directive: ObjectDirective<HTMLImageElement, ImgZoomOptions> = {
  //@ts-ignore
  bind(el: HTMLImageElement) {
    injectGlobalStyles();
  },

  mounted(el: any, binding: DirectiveBinding<ImgZoomOptions>) {
    const options = { ...DEFAULT_OPTIONS, ...binding.value };

    // 关键：为图片添加容器（用于隐藏放大时的溢出部分）
    const container = document.createElement('div');
    container.className = 'v-img-zoom-container';
    // 复制图片的父容器样式（避免布局错乱）
    container.style.display = 'inline-block';
    container.style.position = 'relative';
    container.style.lineHeight = '0'; // 解决 inline-block 基线对齐问题

    // 存储原始图片的父元素和兄弟节点（用于后续恢复）
    const parent = el.parentNode;
    const nextSibling = el.nextSibling;

    // 将图片移动到容器中
    container.appendChild(el);
    // 将容器插入到原始位置
    if (parent && nextSibling) {
      parent.insertBefore(container, nextSibling);
    } else if (parent) {
      parent.appendChild(container);
    }

    // 为图片添加基础样式
    el.classList.add('v-img-zoom');
    el.style.transform = 'scale(1)'; // 初始缩放
    el.style.transformOrigin = options.origin;
    el.style.transitionDuration = `${options.duration}s`;

    // 鼠标进入：放大图片
    const handleMouseEnter = () => {
      el.style.transform = `scale(${options.scale})`;
    };

    // 鼠标离开：恢复原状
    const handleMouseLeave = () => {
      el.style.transform = 'scale(1)';
    };

    // 绑定事件（监听容器的鼠标事件，避免图片本身有空白区域）
    container.addEventListener('mouseenter', handleMouseEnter);
    container.addEventListener('mouseleave', handleMouseLeave);

    // 存储数据供后续使用
    (el as any).vImgZoomData = {
      container,
      parent,
      options,
      handlers: { handleMouseEnter, handleMouseLeave },
    };
  },

  updated(el: HTMLImageElement, binding: DirectiveBinding<ImgZoomOptions>) {
    if (!binding.value) return;

    const data = (el as any).vImgZoomData;
    if (!data) return;

    // 更新配置
    const options = { ...data.options, ...binding.value };
    data.options = options;

    // 更新样式
    el.style.transformOrigin = options.origin;
    el.style.transitionDuration = `${options.duration}s`;
  },

  unmounted(el: HTMLImageElement) {
    const data = (el as any).vImgZoomData;
    if (data) {
      // 移除事件监听
      data.container.removeEventListener('mouseenter', data.handlers.handleMouseEnter);
      data.container.removeEventListener('mouseleave', data.handlers.handleMouseLeave);

      // 将图片从容器中移出，恢复原始结构
      if (data.container.contains(el)) {
        data.container.removeChild(el);
      }

      // 将图片放回原始父节点
      if (data.parent && !el.parentNode) {
        data.parent.appendChild(el);
      }

      // 清理样式和数据
      el.classList.remove('v-img-zoom');
      el.style.transform = '';
      el.style.transformOrigin = '';
      el.style.transitionDuration = '';
      delete (el as any).vImgZoomData;
    }
  },
};

// 全局注册指令
export const setupImgZoomDirective = (app: App) => {
  app.directive('img-zoom', directive);
};

export default directive;
